package middleware

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"net/http"
	"time"
	"webook/internal/web"
)

type LoginMiddlewareBuilder struct {
	ignorePaths []string
	jwtHdl      web.IJwtHandler
}

func NewLoginMiddlewareBuilder(jwtJdl web.IJwtHandler) *LoginMiddlewareBuilder {
	return &LoginMiddlewareBuilder{
		jwtHdl: jwtJdl,
	}
}

func (m *LoginMiddlewareBuilder) IgnorePath(path string) *LoginMiddlewareBuilder {
	m.ignorePaths = append(m.ignorePaths, path)
	return m
}

func (m *LoginMiddlewareBuilder) Build() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var curPath = ctx.Request.URL.Path
		for _, ignorePath := range m.ignorePaths {
			if curPath == ignorePath {
				// 不需要登录校验
				return
			}
		}
		// 进行登录校验
		session := sessions.Default(ctx)
		userId := session.Get("userId")
		if userId == nil {
			// 终止后续流程
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		// 刷新登录态(每隔10min检验)
		nowTime := time.Now().Unix()
		updateTimeStr := session.Get("updateTime")
		if updateTimeStr == nil {
			// 说明是登录后第一次访问
			// 刷新登录态
			session.Set("userId", userId)
			session.Set("updateTime", nowTime)
			session.Options(sessions.Options{
				MaxAge: 60 * 60,
			})
			session.Save()
			return
		}
		updateTime := updateTimeStr.(int64)
		if nowTime-updateTime >= 10*60 {
			// 刷新登录态
			session.Set("userId", userId)
			session.Set("updateTime", nowTime)
			session.Options(sessions.Options{
				MaxAge: 60,
			})
			session.Save()
		}
	}
}

func (m *LoginMiddlewareBuilder) BuildByJWT() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var curPath = ctx.Request.URL.Path
		for _, ignorePath := range m.ignorePaths {
			if curPath == ignorePath {
				// 不需要登录校验
				return
			}
		}
		// 校验token
		token, err := m.jwtHdl.ExtractToken(ctx)
		if err != nil {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		var userClaims web.UserClaims
		parse, err := jwt.ParseWithClaims(token, &userClaims, func(token *jwt.Token) (interface{}, error) {
			return web.AccessTokenKey, nil
		})
		if err != nil || !parse.Valid {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		// 解析UserAgent进行登录校验
		if userClaims.UserAgent != ctx.Request.UserAgent() {
			// TODO: 监控告警并埋点
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		// 校验是否已经退出登录
		checkSsid, err := m.jwtHdl.CheckSsid(ctx, userClaims.Ssid)
		if err != nil || checkSsid {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		// 将userId放入ctx中
		ctx.Set("userId", userClaims.Uid)
		// 将ssid放入ctx中
		ctx.Set("ssid", userClaims.Ssid)
	}
}
